//
//  main.m
//  copy
//
//  Created by admin on 2019/8/9.
//  Copyright © 2019 猫爷爷的酱醋茶. All rights reserved.
//

/*
 
 copy - 是一个方法，定义在NSObject类中，作用：拷贝对象。
    无论是在MRC还是ARC下，如果属性的类型是NSString类型的，@property参数使用copy
 
    copy方法的确是定义在NSObject类的一个方法
    copy方法的内部调用了另外一个方法，copyWithZone:
    这个方法是定义在NSCoping协议之中的。
 
    因为我们类没有遵守NSCoping协议，那么我们的类中就没有copyWithZone:这个方法
    所以，当我们自定义的类调用copy方法时，就会报错
 
    如果我们想要我们自定义的类具备对象拷贝的能力，那么就让我们的类遵守NSCoping协议
    并实现copyWithZone:
 
 特点：
     NSString --> copy --> 没有产生新对象，这种拷贝叫做浅拷贝
     NSMutableString --> copy --> 有产生新对象，这种拷贝叫做深拷贝，而且是copy出的是不可变的字符串NSString。
 
     NSString --> mutableCopy --> 产生可变的新对象，深拷贝
     NSMutableString --> mutableCopy --> 产生可变的新对象，深拷贝
 
 字符串对象拷贝的引用计数器
    a）若对象存储在常量区中，常量区中的数据是不允许被回收的，只有程序结束才能被回收
       所以存储在常量区的字符串对象的引用计数器是一个超级大的数。并且retain和releas无效
 
    b）若字符串存储在堆区，这个字符串对象和普通对象一样，计数器默认是1.
 
    c）字符串对象如果是浅拷贝，会将引用计数器+1
       字符串对象如果是深拷贝，原来的对象的引用计数器不变，新拷贝出来的对象的引用计数器加1.
 
 
 */

#import <Foundation/Foundation.h>
#import "Person.h"

//NSString NSMutableString copy
void NSStringAndNSMutableStringForCopy(void);

//NSString NSMutableString mutableCopy
void NSStringAndNSMutableStringForMutbaleCopy(void);

//字符串的引用计数器
void TheRetainCountOfString(void);

int main(int argc, const char * argv[])
{
    
    Person *p1 = [Person new];
    p1.name = @"猫爷爷的酱醋茶";
    p1.age = 22;
    
    Person *p2 = [p1 copy];
    //两个地址不同，深拷贝
    NSLog(@"p1 = %p,%@的年龄为%d岁",p1,p1.name,p1.age);
    NSLog(@"p2 = %p,%@的年龄为%d岁",p2,p2.name,p2.age);
    
   
    return 0;
}

//字符串的引用计数器
void TheRetainCountOfString(void)
{
    NSString *str1 = @"猫爷爷的酱醋茶"; //存储在常量区 不允许被回收 引用计数器超级大
    NSString *str2 = [NSString stringWithFormat:@"IOS开发者"]; //存储在堆区
    
    NSLog(@"str1的引用计数器为%lu",str1.retainCount);
    NSLog(@"str2的引用计数器为%lu",str2.retainCount);
    
    NSString *strCopy1 = [str2 copy]; //浅拷贝 引用计数器+1
    NSLog(@"\n\t进行浅拷贝之后\n\tstrCopy1 = %p\n\tstr2 = %p,引用计数器为%lu",strCopy1,str2, str2.retainCount);
    
    NSString *strCopy2 = [str2 mutableCopy]; //深拷贝 引用计数器不变
    NSLog(@"\n\t进行深拷贝之后\n\tstrCopy2 = %p\n\tstr2 = %p,引用计数器为%lu",strCopy2,str2, str2.retainCount);
    
    
    
}

//NSString NSMutableString mutableCopy
void NSStringAndNSMutableStringForMutbaleCopy(void)
{
    
    NSString *str1 = @"猫爷爷的酱醋茶";
    NSMutableString *str2 = [str1 mutableCopy];
    
    [str2 appendString:@" IOS开发者"];//说明mutbleCopy返回的是NSMutableString的类型
    
    //有参数新对象
    NSLog(@"str1的地址为%p，str1的内容为%@",str1,str1);
    NSLog(@"str2的地址为%p，str2的内容为%@",str2,str2);
    
    NSMutableString *strOne = [NSMutableString stringWithFormat:@"IOS中级工程师"];
    NSMutableString *strTwo = [strOne mutableCopy];
    
    //地址不同，产生了新对象
    NSLog(@"strOne的地址为%p，strOne的内容为%@",strOne,strOne);
    NSLog(@"strTwo的地址为%p，strTwo的内容为%@",strTwo,strTwo);
}

//NSString NSMutableString copy
void NSStringAndNSmutableStringForCopy(void)
{
    NSString *str1 = @"猫爷爷的酱醋茶";
    //浅拷贝 - 拷贝没有产生新对象
    NSString *str2 = [str1 copy];
    
    //没有产生新对象，地址一样
    NSLog(@"str1的地址为%p，str1的内容为%@",str1,str1);
    NSLog(@"str2的地址为%p，str2的内容为%@",str2,str2);
    
    NSMutableString *strOne = [NSMutableString stringWithFormat:@"IOS开发者"];
    NSMutableString *strTwo = [strOne copy];
    
    //崩溃在此 所以说名copy返回的对象是NSString不可变类型的，故strTwo的正确类型 NSString *strTwo = [strOne copy];
    //[strTwo appendString:@"初级"];
    
    //地址不同，产生了新对象
    NSLog(@"strOne的地址为%p，strOne的内容为%@",strOne,strOne);
    NSLog(@"strTwo的地址为%p，strTwo的内容为%@",strTwo,strTwo);
    
}


